package apiexample.transform.descriptionextraction;

import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import util.StringDealer;

import apiexample.transform.datastructure.UsageExample;

import com.apiexample.server.entity.DescriptionEntity;

import dao.entity.SegmentEntity;

public class SimpleDescriptionExtraction implements DescriptionExtraction {

	@Override
	public ArrayList<DescriptionEntity> getFollowingDescriptionsOfCode(ArrayList<SegmentEntity> segments,
			UsageExample example, int indexOfCode, int maxLen) {
		long time_1 = System.currentTimeMillis();
		// the index of this code segment in the page
		int i = indexOfCode;
		ArrayList<DescriptionEntity> result = new ArrayList<DescriptionEntity>();
		int textLength = 0;
		softBreakTagCount = 0;// return to initial
		for (int j = 1;; j++) {
			int des_index = i + j;
			if (des_index < segments.size()) {
				SegmentEntity thisSegment = segments.get(des_index);
				// stop condition 4: encounter code segment
				if (thisSegment.getType() == SegmentEntity.NON_CODE_SEGMENT) {
					String content = thisSegment.getContent();
					if (j == 1) {
						// judge whether at lest two elements declared by the code snippet are mentioned by the text
						// only try to extract hind descriptive texts for a code block if the text block immediately
						// following the code block mentions the programming elements declared by the code block
						if (!shouldShowFollowingDes(content, example)) {
							break;
						} else {
							System.out.println("Should show following descriptions for example:"
									+ example.getEntity().getId());
						}
					}
					// if the length has not reached the minmum requirement,
					// continue merge. otherwise, break;
					if (textLength > maxLen) {
						break;
					}
					if (thisSegment.getType() == SegmentEntity.SPAM_SEGMENT) {
						break;
					}
					if (isContentBreak(thisSegment)) {
						// stop condition 3: encounter content break tag
						// do not add the content of break to the text
						break;
					}

					// index of preceding text is positive 3 2 1; index of following text is negative -1 -2 -3
					// DescriptionEntity desEntity = new DescriptionEntity(-1, -1*j,
					// -1, KeywordsHighLighter.hightLight(content, example.declaredElementNames,
					// example.referencedElementNames, DELIMITERS, true, BEGINTAG, ENDTAG));
					DescriptionEntity desEntity = new DescriptionEntity(-1, -1 * j, -1, content);
					result.add(desEntity);

					textLength += StringDealer.countTokens(content);

				} else {
					break;
				}
			} else {
				break;
			}
		}
		System.out.println("[INFO]Get descirption time cost:" + (System.currentTimeMillis() - time_1));
		return result;
	}

	@Override
	public ArrayList<DescriptionEntity> getPrecedingDescriptionsOfCode(ArrayList<SegmentEntity> segments,
			UsageExample example, int indexOfCode, int maxLen) {
		long time_1 = System.currentTimeMillis();
		// the index of this code segment in the page
		int i = indexOfCode;
		ArrayList<DescriptionEntity> result = new ArrayList<DescriptionEntity>();
		int textLength = 0;
		softBreakTagCount = 0;// return to initial
		for (int j = 1;; j++) {
			int des_index = i - j;
			if (des_index >= 0) {
				SegmentEntity thisSegment = segments.get(des_index);
				// stop condition 4: encounter code segment
				if (thisSegment.getType() == SegmentEntity.NON_CODE_SEGMENT) {

					// stop condition 1: if the length has not reached the minmum requirement,
					// continue merge. otherwise, break;
					if (textLength > maxLen) {
						break;
					}

					// stop condition 2: spam content
					if (thisSegment.getType() == SegmentEntity.SPAM_SEGMENT) {
						break;
					}

					String content = thisSegment.getContent();
					// index of preceding text is positive 3 2 1; index of following text is negative -1 -2 -3

					DescriptionEntity desEntity = new DescriptionEntity(-1, j, -1, content);
					result.add(desEntity);
					textLength += StringDealer.countTokens(content);

					if (isContentBreak(thisSegment)) {
						// stop condition 3: encounter content break tag
						// add the content of break to the text
						break;
					}

				} else {
					break;
				}
			} else {
				break;
			}
		}
		System.out.println("[INFO]Get descirption time cost:" + (System.currentTimeMillis() - time_1));
		return result;
	}

	public boolean shouldShowFollowingDes(String content, UsageExample example) {
		StringTokenizer tokenizer = new StringTokenizer(content);
		int count = 0;
		while (tokenizer.hasMoreTokens()) {
			String token = tokenizer.nextToken();
			if (example.declaredTypeNames.contains(token) || example.declaredMethodNames.contains(token)) {
				count++;
				if (count >= 1) {
					return true;// should
				}
			}
		}
		return false;
	}

	/*
	 * The following is used for judge whether the segment being processed is a content break
	 */
	public static String[] hardContentBreakTag = { "h1", "h2", "h3", "h4", "h5", "h6", "hr", "ol", "ul" };
	public static String[] softContentBreakTag = { "table", "div", "tr" };

	private static int softBreakTagCount = 0;

	public static boolean isContentBreak(SegmentEntity segment) {
		StringBuffer hardBuffer = new StringBuffer();
		StringBuffer softBuffer = new StringBuffer();
		for (int i = 0; i < hardContentBreakTag.length; i++) {
			if (i != 0) {
				hardBuffer.append("|");
			}
			hardBuffer.append(hardContentBreakTag[i]);
		}
		for (int i = 0; i < softContentBreakTag.length; i++) {
			if (i != 0) {
				softBuffer.append("|");
			}
			softBuffer.append(softContentBreakTag[i]);
		}
		String hard_str_pattern = "(.*?)<(\\s*?)(" + hardBuffer.toString() + ")(.*?)>(.*?)";
		String soft_str_pattern = "(.*?)<(\\s*?)(" + softBuffer.toString() + ")(.*?)>(.*?)";

		// System.out.println(str_pattern);
		Pattern hard_pattern = Pattern.compile(hard_str_pattern, Pattern.CASE_INSENSITIVE);
		Matcher hard_matcher = hard_pattern.matcher(segment.getBegin_tag());
		if (hard_matcher.matches()) {
			System.out.println("[Content break]Hard content break match!" + segment.getPage_id() + " "
					+ segment.getBegin_tag());
			return true;
		}

		Pattern soft_pattern = Pattern.compile(soft_str_pattern, Pattern.CASE_INSENSITIVE);
		Matcher soft_matcher = soft_pattern.matcher(segment.getBegin_tag());
		// System.out.println(hard_matcher.matches());
		// System.out.println(soft_matcher.matches());
		while (soft_matcher.find()) {
			softBreakTagCount++;
		}
		if (softBreakTagCount > 2) {
			System.out.println("[Content break]Soft content break match!" + segment.getPage_id() + " "
					+ segment.getBegin_tag());
			return true;
		}
		return false;
	}
}
